package com.zhu.tool_test.plugins;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hitotek.util.TopDateUtil;
import core.MultipartData;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import util.DateUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @program: tool_test
 * @description:
 * @author: ggBall
 * @create: 2020-11-16 09:43
 **/
@Slf4j
public abstract class ExcleExportAbs {

    private static LinkedList<String> codeList = new LinkedList<>();


    /**
    * @Description
    * @Author  ggBall
    * @Date   2020/11/16 12:18
    * @Param
     * @param response
     * @param fileName 文件名
     * @param body 列表数据
     * @param head 表头
    * @Return      void
    * @Exception
    *
    */
    public static void dynamicWrite(HttpServletResponse response, String fileName, List<MultipartData> body, String head){

        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        try {
            fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 导出表格
        EasyExcel.write(out,null)
                .head(createHead(head))
                .sheet(fileName)
                // 自动列宽
                .registerWriteHandler(new CustomCellWriteHandler())
                // 设置样式
                .registerWriteHandler(setStyle())
                .doWrite(createBody(body));
    };

    /**
    * @Description 设置表格样式
    * @Author  ggBall
    * @Date   2020/11/16 12:03
    * @Param
    * @Return      com.alibaba.excel.write.style.HorizontalCellStyleStrategy
    * @Exception
    *
    */
    public static HorizontalCellStyleStrategy setStyle(){

        // 设置样式
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //设置背景颜色
        headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        //设置头字体
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short)13);
        headWriteFont.setBold(true);
        headWriteCellStyle.setWriteFont(headWriteFont);
        //设置头居中
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

        //内容策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //设置 水平居中
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

        return horizontalCellStyleStrategy;
    }

    /**
    * @Description 生成表身
    * @Author  ggBall
    * @Date   2020/11/16 12:07
    * @Param
     * @param body
    * @Return      java.util.List<java.util.List<java.lang.String>>
    * @Exception
    *
    */
    private static List<List<String>> createBody(List<MultipartData> body){
        // 选择要取出的部分
        List<List<String>> bodies = body.stream().map(data -> {
            LinkedList<String> list = new LinkedList<>();
            codeList.stream().forEach(code -> {
                        // 对时间特殊处理
                        if ("sampleTime".equals(code)) {
                            String sampleTime = DateUtils.format(data.getDatePart(code), TopDateUtil.YYYY_MM_DD_HH_MM_SS);
                            list.add(sampleTime);
                            return;
                        }
                        // 对null值进行特殊处理
                        if (null == data.get(code)) {
                            list.add("-");
                            return;
                        }
                        list.add(String.valueOf(data.get(code)));
                    }

            );
            return list;
        }).collect(Collectors.toList());

        return bodies;
    }


    private static List<List<String>> createHead(String headJson){
        // 清除codeList
        codeList.clear();

        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode jsonNode = null;
        try {
            jsonNode = objectMapper.readTree(headJson);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        // 打印list
        log.info("jsonNode:{}",jsonNode);
        // 转换成 list<list<String>>
        LinkedList<List<String>> outList = new LinkedList<>();
        JsonNode head = jsonNode.get("head");
        // 判断表头是否为数组
        if(null != head && head.isArray()) {
            // 循环遍历数组里的表头数据
            for (int j=0;j<head.size();j++) {
                JsonNode nodeList = head.get(j);
                // 创建list
                LinkedList<String> list = new LinkedList<>();
                for (int i = 0; i < nodeList.size(); i++) {
                    JsonNode node = nodeList.get(i);
                    // 如果node为null
                    if (null == node || node.size() == 0) {
                        continue;
                    }
                    log.info("node:{}", node);
                    String code = node.get("code").asText();
                    String name = node.get("name").asText();

                    list.add(name);
                    // 将标头的code保存下来
                    if (null == code || "".equals(code)) {
                        continue;
                    }
                    codeList.add(code);
                }
                // 最后保存成head需要的list<List<String>>
                outList.add(list);
            }

        } else if (null == head) {
            log.info("head为空");
        }
        log.info("outList:{}",outList);
        return outList;
    }


    /**
     * @author jamin
     * @date 2020/7/29 11:28
     * 设置自适应列宽
     */
    public static class CustomCellWriteHandler extends AbstractColumnWidthStyleStrategy {
        private Map<Integer, Map<Integer, Integer>> CACHE = new HashMap<>();

        @Override
        protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head, Integer integer, Boolean isHead) {
            boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
            if (needSetWidth) {
                Map<Integer, Integer> maxColumnWidthMap = CACHE.get(writeSheetHolder.getSheetNo());
                if (maxColumnWidthMap == null) {
                    maxColumnWidthMap = new HashMap<>();
                    CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);
                }

                Integer columnWidth = this.dataLength(cellDataList, cell, isHead);
                if (columnWidth >= 0) {
                    if (columnWidth > 255) {
                        columnWidth = 255;
                    }

                    Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());
                    if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
                        maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);
                        writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256);
                    }

                }
            }
        }

        private Integer dataLength(List<CellData> cellDataList, Cell cell, Boolean isHead) {
            if (isHead) {
                return cell.getStringCellValue().getBytes().length;
            } else {
                CellData cellData = cellDataList.get(0);
                CellDataTypeEnum type = cellData.getType();
                if (type == null) {
                    return -1;
                } else {
                    switch (type) {
                        case STRING:
                            return cellData.getStringValue().getBytes().length;
                        case BOOLEAN:
                            return cellData.getBooleanValue().toString().getBytes().length;
                        case NUMBER:
                            return cellData.getNumberValue().toString().getBytes().length;
                        default:
                            return -1;
                    }
                }
            }
        }
    }

}
